package main

import (
    "fmt"
    "reflect"
)
/*
map 学习总结，
debug函数：打印以下标题，之后是实例代码。可以在实例中添加或者修改相关的代码进行试验学习
printMap: 打印map是否为nil, 长度。

1，声明map
2,创建map
2.1,不指定长度创建map
2.1.1,不指定长度创建map，并添加数据
2.2,指定长度创建map
2.2.1,指定长度创建map，并添加数据
2.3 直接赋值创建map
2.3.1 map中追加数据
3,删除操作
4,查找元素
4.1,查找元素, key不存在时，value为0
4.2,双返回值, 第一个返回值为key对应的值，第二个返回值为bool类型，元素是否存在
4.3, 判断元素"vivio"是否存在
5,修改元素
6,遍历map，注意，每次运行的结果，遍历顺序都不是相同的
6.1,遍历map，只遍历key
6.2,遍历map，只遍历value
7, 对map取地址
7.1, 指针格式打印map,&map:
7.2, 指针格式打印map["vilen"]:
7.2.1, 指针格式打印&ages2["vilen"]:编译报错
8, map做为函数参数
8.1, map做为函数参数传递, 并修改vilen年龄为100
8.2, &map做为函数参数传递, 并修改vilen年龄为22
9, map的比较
9.1, map的比较，(ages2 == ages3) 比较，编译错误
9.2, map的比较，reflect.DeepEqual比较
9.2.1, map的比较，修改ages3[alice]=32
10 map的零值
*/
// 颜色板，将print打印成特殊颜色，方便查看对应的输出结果
const (
    TextBlack = iota + 30
    TextRed
    TextGreen
    TextYellow
    TextBlue
    TextMagenta
    TextCyan
    TextWhite
)

//将说明打印成蓝色
func debug(s string) {
    fmt.Printf("\x1b[0;%dm%s\x1b[0m\n", TextBlue, s)
}

//判断map是否为nil, 并打印map的值，和map的长度
func printMap(m map[string]int) {
    fmt.Println("map data:")
    if m == nil {
        fmt.Println("\t map is nil")
    } else {
        fmt.Println("\t map is NOT nil")
    }
    fmt.Println("\t", m, ", map len =", len(m))
}

// 修改map测试函数，测试map做为参数的情况
func modifyMap(m map[string]int) {
    fmt.Printf("map %p\n", m)
    fmt.Printf("&map %p\n", &m)
    m["vilen"] = 100
}

// 修改map测试函数，测试&map做为参数的情况
func modifyMapP(m *map[string]int) {
    x := *m
    fmt.Printf("map %p\n", m)
    fmt.Printf("&map %p\n", &m)
    fmt.Printf("*(&map) %p\n", x)
    x["vilen"] = 22
}

func main() {
    debug("1，声明map")
    var names map[string]int
    printMap(names)
    //names["vilen"]=24	//编译出错panic: assignment to entry in nil map

    debug("2,创建map")
    debug("2.1,不指定长度创建map")
    ages := make(map[string]int)
    printMap(ages)
    debug("2.1.1,不指定长度创建map，并添加数据")
    ages["vilen"] = 10
    printMap(ages)

    debug("2.2,指定长度创建map")
    ages1 := make(map[string]int, 10)
    printMap(ages1)
    debug("2.2.1,指定长度创建map，并添加数据")
    ages1["vilen"] = 10
    printMap(ages1)

    debug("2.3 直接赋值创建map")
    ages2 := map[string]int{
        "alice":    31,
        "charltie": 34,
        "vilen":    22, // 必须有逗号
    }
    printMap(ages2)
    debug("2.3.1 map中追加数据")
    ages2["vivio"] = 33
    printMap(ages2)

    debug("3,删除操作")
    delete(ages2, "vivio")
    printMap(ages2)

    debug("4,查找元素")
    debug("4.1,查找元素, key不存在时，value为0")
    fmt.Println("vivio's age=", ages2["vivio"])
    fmt.Println("vilen's age=", ages2["vilen"])
    debug("4.2,双返回值, 第一个返回值为key对应的值，第二个返回值为bool类型，元素是否存在")
    v, b := ages2["vilen"]
    fmt.Printf("v:%T %v,  b:%T %v\n", v, v, b, b)
    debug("4.3, 判断元素\"vivio\"是否存在")
    if _, exists := ages2["vivio"]; exists {
        fmt.Println("vivio'age exists")
    } else {
        fmt.Println("vivio'age not exist")
    }

    debug("5,修改元素")
    ages2["vilen"] = 25
    fmt.Println("vilen's age=", ages2["vilen"])
    printMap(ages2)

    debug("6,遍历map，注意，每次运行的结果，遍历顺序都不是相同的")
    for name, age := range ages2 {
        fmt.Printf("%s\t%d\n", name, age)
    }
    debug("6.1,遍历map，只遍历key")
    for name := range ages2 {
        fmt.Printf("%s\n", name)
    }
    debug("6.2,遍历map，只遍历value")
    for _, age := range ages2 {
        fmt.Printf("%d\n", age)
    }

    debug("7, 对map取地址")
    debug("7.1, 指针格式打印map,&map:")
    fmt.Printf("ages2 address %p\n", ages2)
    fmt.Printf("&ages2 address %p\n", &ages2)
    debug("7.2, 指针格式打印map[\"vilen\"]:")
    fmt.Printf("map[vilen] address %p\n", ages2["vilen"])
    debug("7.2.1, 指针格式打印&ages2[\"vilen\"]:编译报错")
    //fmt.Printf("&map[vilen] address %p\n", &ages2["vilen"])//编译报错

    //map是引用类型，做为参数传递，修改的是指向的内容
    debug("8, map做为函数参数")
    debug("8.1, map做为函数参数传递, 并修改vilen年龄为100")
    modifyMap(ages2)
    printMap(ages2)
    debug("8.2, &map做为函数参数传递, 并修改vilen年龄为22")
    modifyMapP(&ages2)
    printMap(ages2)

    debug("9, map的比较")
    ages3 := map[string]int{
        "alice":    31,
        "charltie": 34,
        "vilen":    22, // 必须有逗号
    }
    printMap(ages2)
    printMap(ages3)
    debug("9.1, map的比较，(ages2 == ages3) 比较，编译错误")
    //map can only be compared to nil
    /*
    	if ages2 == ages3 {//只能和nil进行比较，编译错误
    		fmt.Printf("true")
    }*/

    debug("9.2, map的比较，reflect.DeepEqual比较")
    fmt.Println("reflect.DeepEqual(ages3,ages2) = ", reflect.DeepEqual(ages3, ages2))

    debug("9.2.1, map的比较，修改ages3[alice]=32")
    ages3["alice"] = 32
    printMap(ages3)
    fmt.Println("reflect.DeepEqual(ages3,ages2) = ", reflect.DeepEqual(ages3, ages2))

    debug("10 map的零值")
    var names1 map[string]int
    names2 := make(map[string]int)
    printMap(names1)
    printMap(names2)

    debug("11 map key 不存在时")
    var names3 map[string]struct{name string}
    fmt.Println(".", names3["123"])

}
